package kidsProjectClient;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.AbstractMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;

public class ServerNode {

	private String opseg;
	private int mojPort, MAX_NUM_OF_CLIENTS = 2;
	private DatagramSocket serverSocket;
	private byte[] receiveData, sendData;
	private DatagramPacket receivePacket;
	private List<Entry<InetAddress, Integer>> myClients, servers;

	public ServerNode(String opseg, DatagramSocket clientSocket) {
		System.out.println("NEW SERVER NODE!!!");
		this.opseg = opseg;
		this.mojPort = clientSocket.getLocalPort();
		clientSocket.close();
		try {
			serverSocket = new DatagramSocket(this.mojPort,
					InetAddress.getLocalHost());
			receiveData = new byte[512];
			sendData = new byte[512];
			receivePacket = new DatagramPacket(receiveData, receiveData.length);
			myClients = new LinkedList<Entry<InetAddress, Integer>>();
			servers = new LinkedList<Entry<InetAddress, Integer>>();

		} catch (SocketException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public ServerNode(String mojOpseg, DatagramSocket clientSocket,
			List<Entry<InetAddress, Integer>> servers) {
		System.out.println("NEW SERVER NODE!!!");
		this.opseg = opseg;
		this.mojPort = clientSocket.getLocalPort();
		clientSocket.close();
		try {
			serverSocket = new DatagramSocket(this.mojPort,
					InetAddress.getLocalHost());
			receiveData = new byte[512];
			sendData = new byte[512];
			receivePacket = new DatagramPacket(receiveData, receiveData.length);
			myClients = new LinkedList<Entry<InetAddress, Integer>>();
			this.servers = new LinkedList<Entry<InetAddress, Integer>>(servers);
		} catch (SocketException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void start() {
		Thread communication = new Thread(new Runnable() {
			@Override
			public void run() {
				while (true) {
					receiveData = new byte[512];
					try {
						serverSocket.receive(receivePacket);
						System.out.println("KLIJENATA: " + myClients);
						String request = new String(receivePacket.getData())
								.trim();
						if (request.startsWith("[ADD_NEW_SERVER]|")) {
							String[] split = request.split("\\|");
							InetAddress newServerAddress = InetAddress
									.getByName(split[1].split(":")[0]);
							int newServerPort = Integer.parseInt(split[1]
									.split(":")[1]);
							servers.add(new AbstractMap.SimpleEntry<InetAddress, Integer>(
									newServerAddress, newServerPort));
						}
						if (request.equals("[REGISTER_REQUEST]|[NEW_CLIENT]")) {

							int newClientPort = receivePacket.getPort(); // port
																			// novog
																			// klijenta
							InetAddress newClientAddress = receivePacket
									.getAddress(); // Adresa novog klijenta
							// TODO srediti broj klijenata koji mogu da se
							// nakace na server

							if (myClients.size() > MAX_NUM_OF_CLIENTS) {
								// TODO cantraj sa serverima, pitaj da li neki
								// moze da ga primi, ako ne onda novi klijen
								// postaje server i salju mu se dva servera
								// izmedju kojih ce da se bocne, ako neko moze
								// salje mu se adresa tog servera, bane je gej

								for (Entry<InetAddress, Integer> curServer : servers) {
									request = "[NEED_CLIENTS?]";
									sendData = request.getBytes();
									DatagramPacket sendPacket = new DatagramPacket(
											sendData, sendData.length,
											curServer.getKey(), curServer
													.getValue());

									serverSocket.send(sendPacket);

								}
								int responses = 0, otherServerPort = 0;
								InetAddress otherServerAddress = null;
								boolean newServer = false;
								while (true) {
									receiveData = new byte[512];
									receivePacket = new DatagramPacket(
											receiveData, receiveData.length);
									serverSocket.receive(receivePacket);
									String data = new String(receivePacket
											.getData()).trim();
									if (data.equals("[YES_I_DO]")) {
										newServer = false;
										otherServerAddress = receivePacket
												.getAddress();
										otherServerPort = receivePacket
												.getPort();
										break;
									}
									if (data.equals("[NO_I_DONT]")) {
										responses++;
									}
									if (responses == servers.size()) {
										newServer = true;
										break;// novi server
									}
								}

								if (!newServer) {

									for (Entry<InetAddress, Integer> curServer : servers) { // GOVORIMO
																							// OSTALIM
																							// SERVERIMA
																							// DA
																							// DODAJU
																							// NOVI
																							// SERVER
										request = "[ADD_NEW_SERVER]|"
												+ otherServerAddress
														.getHostName() + ":"
												+ otherServerPort;
										sendData = request.getBytes();
										DatagramPacket sendPacket = new DatagramPacket(
												sendData, sendData.length,
												curServer.getKey(), curServer
														.getValue());

										serverSocket.send(sendPacket);

									}

									String response = "[REGISTER_RESPONSE_SERVER]|[NEW_SERVER]|"
											+ otherServerAddress.getHostName()
											+ ":" + otherServerPort;

									sendData = response.getBytes();
									DatagramPacket sendPacket = new DatagramPacket(
											sendData, sendData.length,
											newClientAddress, newClientPort);

									serverSocket.send(sendPacket);

								} else {

									servers.add(new AbstractMap.SimpleEntry<InetAddress, Integer>(
											newClientAddress, newClientPort));

									String response = "[REGISTER_RESPONSE_SERVER]|[ROLE_SERVER]|"
											+ serverSocket.getLocalAddress()
													.getHostName()
											+ ":"
											+ serverSocket.getLocalPort();
									sendData = response.getBytes();
									DatagramPacket sendPacket = new DatagramPacket(
											sendData, sendData.length,
											newClientAddress, newClientPort);

									serverSocket.send(sendPacket); // Slanje
																	// adrese
																	// i
																	// porta
																	// novom
																	// klijentu

									for (Entry<InetAddress, Integer> curServer : servers) {
										response = "[LIST_OF_SERVERS]|"
												+ serverSocket
														.getLocalAddress()
														.getHostName()
												+ ":"
												+ serverSocket.getLocalPort()
												+ "|"
												+ curServer.getKey()
														.getHostName() + ":"
												+ curServer.getValue();
										sendData = response.getBytes();
										sendPacket = new DatagramPacket(
												sendData, sendData.length,
												newClientAddress, newClientPort);

										serverSocket.send(sendPacket);
									}
									serverSocket.send(sendPacket);
									response = "[END_LIST_OF_SERVERS]|"
											+ serverSocket.getLocalAddress()
													.getHostName() + ":"
											+ serverSocket.getLocalPort();
									sendData = response.getBytes();
									sendPacket = new DatagramPacket(sendData,
											sendData.length, newClientAddress,
											newClientPort);

									serverSocket.send(sendPacket);

								}
							} else {

								myClients
										.add(new AbstractMap.SimpleEntry<InetAddress, Integer>(
												newClientAddress, newClientPort));

								String response = "[REGISTER_RESPONSE_SERVER]|[ROLE_CLIENT]|"
										+ serverSocket.getLocalAddress()
												.getHostName()
										+ ":"
										+ serverSocket.getLocalPort();

								sendData = response.getBytes();
								DatagramPacket sendPacket = new DatagramPacket(
										sendData, sendData.length,
										newClientAddress, newClientPort);

								serverSocket.send(sendPacket); // Slanje adrese
																// i
																// porta novom
																// klijentu

							}
						}
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		});
		communication.start();
	}
}
